package com.serial.socket;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;

import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketFrame;
import com.neovisionaries.ws.client.WebSocketState;
import com.serial.activity.BuildConfig;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public class WsManager {
    public static WsManager mInstance;
    private final String TAG = this.getClass().getSimpleName();

    /**
     * WebSocket config
     */
    private static final int FRAME_QUEUE_SIZE = 5;
    private static final int CONNECT_TIMEOUT = 5000;
    private static final String DEF_TEST_URL = "http://192.168.2.107:8080";//测试服默认地址
    private static final String DEF_RELEASE_URL = "正式服地址";//正式服默认地址
    private static final String DEF_URL = BuildConfig.DEBUG ? DEF_TEST_URL : DEF_RELEASE_URL;
    private String url;

    private Handler mHandler = new Handler();
    private int reconnectCount = 0;//重连次数
    private long minInterval = 3000;//重连最小时间间隔
    private long maxInterval = 60000;//重连最大时间间隔

    private WebSocket ws;
    private WsStatus mStatus;
    private WsListener mListener;


    public static WsManager getInstance(){
        if (mInstance == null){
            synchronized (WsManager.class){
                if (mInstance == null){
                    mInstance = new WsManager();
                }
            }
        }
        return mInstance;
    }

    public void init(){
        try {
            String configUrl = "";
            url = TextUtils.isEmpty(configUrl) ? DEF_URL : configUrl;
            ws = new WebSocketFactory().createSocket(url,CONNECT_TIMEOUT)
                    .setFrameQueueSize(FRAME_QUEUE_SIZE)//设置帧队列最大值为5
                    .setMissingCloseFrameAllowed(false)//设置不允许服务端关闭连接却未发送关闭帧
                    .addListener(mListener = new WsListener())//添加回调监听
                    .connectAsynchronously();//异步连接
            setStatus(WsStatus.CONNECTING);
            Log.i(TAG,"第一次连接");
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    class WsListener extends WebSocketAdapter{
        @Override
        public void onTextMessage(com.neovisionaries.ws.client.WebSocket websocket, String text) throws Exception {
            super.onTextMessage(websocket, text);
            Log.i(TAG,"receive data is:"+text);
        }


        @Override
        public void onConnected(com.neovisionaries.ws.client.WebSocket websocket, Map<String, List<String>> headers) throws Exception {
            super.onConnected(websocket, headers);
            Log.i(TAG,"connect success");
            setStatus(WsStatus.CONNECT_SUCCESS);
            cancelReconnect();
        }

        @Override
        public void onConnectError(com.neovisionaries.ws.client.WebSocket websocket, WebSocketException exception) throws Exception {
            super.onConnectError(websocket, exception);
            Log.i(TAG,"connect error");
            setStatus(WsStatus.CONNECT_FAIL);
            reconnect();
        }

        @Override
        public void onDisconnected(com.neovisionaries.ws.client.WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer) throws Exception {
            super.onDisconnected(websocket, serverCloseFrame, clientCloseFrame, closedByServer);
            Log.i(TAG,"connect fail");
            setStatus(WsStatus.CONNECT_FAIL);
            reconnect();
        }
    }


    public WsStatus getStatus() {
        return mStatus;
    }

    public void setStatus(WsStatus mStatus) {
        this.mStatus = mStatus;
    }

    public void disConnect(){
        if (ws != null){
            ws.disconnect();
        }
    }

    public void reconnect(){
        if (!isNetConnect()) {
            reconnectCount = 0;
            Log.i(TAG,"重连失败网络不可用");
            mHandler.postDelayed(waiteNetEnable,3000);
            return;
        }

        //这里其实应该还有个用户是否登录了的判断 因为当连接成功后我们需要发送用户信息到服务端进行校验
        //由于我们这里是个demo所以省略了
        //*************************************************************************************
        if (ws != null &&
                !ws.isOpen() &&//当前连接断开了
                getStatus() != WsStatus.CONNECTING) {//不是正在重连状态
            reconnectCount++;
            setStatus(WsStatus.CONNECTING);
            long reconnectTime = minInterval;
            if (reconnectCount > 3) {
                url = DEF_URL;
                long temp = minInterval * (reconnectCount - 2);
                reconnectTime = temp > maxInterval ? maxInterval : temp;
            }
            Log.i(TAG,"准备开始第"+reconnectCount+"次重连,重连间隔"+reconnectTime+" -- url:"+url);
            mHandler.postDelayed(mReconnectTask, reconnectTime);
        }
    }

    private Runnable waiteNetEnable = new Runnable() {
        @Override
        public void run() {
            reconnect();
        }
    };

    public void sendData(String data){
        ws.sendText(data);
        Log.i(TAG,"send Data is :"+data);
    }

    private Runnable mReconnectTask = new Runnable() {
        @Override
        public void run() {
            try {
                ws = new WebSocketFactory().createSocket(url, CONNECT_TIMEOUT)
                        .setFrameQueueSize(FRAME_QUEUE_SIZE)//设置帧队列最大值为5
                        .setMissingCloseFrameAllowed(false)//设置不允许服务端关闭连接却未发送关闭帧
                        .addListener(mListener = new WsListener())//添加回调监听
                        .connectAsynchronously();//异步连接
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };

    private void cancelReconnect(){
        reconnectCount = 0;
        mHandler.removeCallbacks(mReconnectTask);
    }

    private boolean isNetConnect(){
        if (WsApplication.getContext() == null){
            return false;
        }
        ConnectivityManager connectivityManager = (ConnectivityManager) WsApplication.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager != null){
            NetworkInfo info = connectivityManager.getActiveNetworkInfo();
            if (info != null && info.isConnected()) {
                // 当前网络是连接的
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    // 当前所连接的网络可用
                    return true;
                }
            }
        }
        return false;
    }
}
